package com.reggie.console.exception;

import com.reggie.common.enums.ResponseCode;
import com.reggie.common.exception.ReggieException;
import com.reggie.console.dto.ResultDTO;
import com.reggie.console.util.ResultBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

/**
 * 全局异常处理
 *
 * @author yth
 * @since 2023-02-05-0:23
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    private static final Set<ResponseCode> busiExceptionCodeSet
            = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
            ResponseCode.CLIENT_ERROR
    )));

    /**
     * 发送对应消息传递给用户，提醒规范操作
     *
     * @param ex 业务异常
     * @return 消息
     */
    @ExceptionHandler(ReggieException.class)
    public ResultDTO<Void> doException(ReggieException ex) {
        final ResponseCode responseCode = ex.getCode();
        if (busiExceptionCodeSet.contains(responseCode)) {
            return doBusinessException(ex);
        } else {
            return doSystemException(ex);
        }
    }

    private ResultDTO<Void> doBusinessException(ReggieException ex) {
        return ResultBuilder.error(ex.getCode(), ex.getMessage());
    }

    /**
     * 发送固定消息传递给用户，安抚用户
     * 发送特定消息给运维人员，提示维护
     * 记录日志
     *
     * @param ex 系统异常
     * @return 消息
     */
    public ResultDTO<Void> doSystemException(ReggieException ex) {
        log.error("code={},msg={}", ex.getCode(), ex.getMessage());
        return ResultBuilder.error(ex.getCode(), "系统异常，请稍后再试！");
    }

    /**
     * 除了自定义的异常处理器，保留对Exception类型的异常处理，用于处理非预期的异常
     * 发送固定消息传递给用户，安抚用户
     * 发送特定消息给编程人员，提示维护（纳入预期范围内）
     * 记录日志
     *
     * @param ex 其他异常
     * @return 消息
     */
    @ExceptionHandler(Exception.class)
    public ResultDTO<Void> doOtherException(Exception ex) {
        log.error("unknown exception: ", ex);
        return ResultBuilder.error(ResponseCode.SYSTEM_ERROR, "系统繁忙，请联系管理员！");
    }
}
